﻿using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Editors;
using EasyXaf.EntityDesigner.BusinessObjects;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Xml.Linq;

namespace EasyXaf.EntityDesigner.Editors.DetailViewEditors.Models;

/// <summary>
/// 面板
/// </summary>
[DomainComponent]
[XafDisplayName("面板")]
public class Panel : Component
{
    private string _caption;
    private LayoutDirection _layoutDirection;
    private DefaultBoolean _isCollapsibleGroup;
    private DefaultBoolean _isGroupCollapsed;
    private bool _isRoot;

    /// <summary>
    /// 标题
    /// </summary>
    [XafDisplayName("标题")]
    public string Caption
    {
        get => _caption;
        set => SetPropertyValue(ref _caption, value);
    }

    /// <summary>
    /// 布局方向
    /// </summary>
    [XafDisplayName("布局方向")]
    public LayoutDirection LayoutDirection
    {
        get => _layoutDirection;
        set => SetPropertyValue(ref _layoutDirection, value);
    }

    /// <summary>
    /// 可展开
    /// </summary>
    [XafDisplayName("可展开")]
    [Appearance("为根面板时隐藏可展开属性", Criteria = "[IsRoot]==true", Visibility = ViewItemVisibility.Hide)]
    public DefaultBoolean IsCollapsibleGroup
    {
        get => _isCollapsibleGroup;
        set => SetPropertyValue(ref _isCollapsibleGroup, value);
    }

    /// <summary>
    /// 展开组
    /// </summary>
    [XafDisplayName("展开组")]
    [Appearance("为根面板时隐藏展开组属性", Criteria = "[IsRoot]==true", Visibility = ViewItemVisibility.Hide)]
    public DefaultBoolean IsGroupCollapsed
    {
        get => _isGroupCollapsed;
        set => SetPropertyValue(ref _isGroupCollapsed, value);
    }

    [Browsable(false)]
    public bool IsRoot
    {
        get => _isRoot;
        set => SetPropertyValue(ref _isRoot, value);
    }

    public ObservableCollection<Component> Components { get; }

    public Panel(Component parent, LayoutDesigner layoutDesigner)
        : base(parent, layoutDesigner)
    {
        Components = [];
    }

    public Component FindComponent(Guid componentId)
    {
        var component = Components.FirstOrDefault(c => c.Oid == componentId);
        if (component == null)
        {
            foreach (var childComponent in Components)
            {
                if (childComponent is Panel panel)
                {
                    component = panel.FindComponent(componentId);
                }
                else if (childComponent is Tabs tabs)
                {
                    component = tabs.FindComponent(componentId);
                }

                if (component != null)
                {
                    break;
                }
            }
        }
        return component;
    }

    public override void WriteToXml(XElement element)
    {
        base.WriteToXml(element);

        if (!string.IsNullOrWhiteSpace(Caption))
        {
            SetXmlAttributeValue(element, "caption", Caption);
        }

        if (IsCollapsibleGroup != DefaultBoolean.Default)
        {
            SetXmlAttributeValue(element, "is-collapsible-group", IsCollapsibleGroup == DefaultBoolean.True ? "true" : "false");
        }

        if (IsGroupCollapsed != DefaultBoolean.Default)
        {
            SetXmlAttributeValue(element, "is-group-collapsed", IsGroupCollapsed == DefaultBoolean.True ? "true" : "false");
        }

        foreach (var component in Components)
        {
            if (component is PropertyEditor propertyEditor)
            {
                var propertyEditorElement = propertyEditor.CreateXElement();
                propertyEditor.WriteToXml(propertyEditorElement);
                element.Add(propertyEditorElement);
            }
            else if (component is Panel panel)
            {
                var panelElement = panel.CreateXElement();
                panel.WriteToXml(panelElement);
                element.Add(panelElement);
            }
            else if (component is Tabs tabs)
            {
                var tabsElement = tabs.CreateXElement();
                tabs.WriteToXml(tabsElement);
                element.Add(tabsElement);
            }
        }
    }

    public override void ReadFromXml(XElement element)
    {
        base.ReadFromXml(element);

        Caption = GetXmlAttributeValue<string>(element, "caption");

        if (element.Name.LocalName == "h")
        {
            LayoutDirection = LayoutDirection.Horizontal;
        }
        else
        {
            LayoutDirection = LayoutDirection.Vertical;
        }

        var isCollapsibleGroup = GetXmlAttributeValue<string>(element, "is-collapsible-group");
        if (isCollapsibleGroup == "true")
        {
            IsCollapsibleGroup = DefaultBoolean.True;
        }
        else if (isCollapsibleGroup == "false")
        {
            IsCollapsibleGroup = DefaultBoolean.False;
        }

        var isGroupCollapsed = GetXmlAttributeValue<string>(element, "is-group-collapsed");
        if (isGroupCollapsed == "true")
        {
            IsGroupCollapsed = DefaultBoolean.True;
        }
        else if (isGroupCollapsed == "false")
        {
            IsGroupCollapsed = DefaultBoolean.False;
        }

        Components.Clear();

        var children = element.Elements();
        foreach (var child in children)
        {
            var elementName = child.Name.LocalName;

            if (elementName == "p")
            {
                var propertyEditor = new PropertyEditor(this, LayoutDesigner);
                propertyEditor.ReadFromXml(child);
                Components.Add(propertyEditor);
            }
            else if (elementName == "h" || elementName == "v")
            {
                var panel = new Panel(this, LayoutDesigner);
                panel.ReadFromXml(child);
                Components.Add(panel);
            }
            else if (elementName == "t")
            {
                var tabs = new Tabs(this, LayoutDesigner);
                tabs.ReadFromXml(child);
                Components.Add(tabs);
            }
        }
    }

    public override XElement CreateXElement()
    {
        if (LayoutDirection == LayoutDirection.Horizontal)
        {
            return new XElement("h");
        }
        else
        {
            return new XElement("v");
        }
    }
}
